home *** CD-ROM | disk | FTP | other *** search
/ Speccy ClassiX 1998 / Speccy ClassiX 98.iso / amiga_system / the_aminet / dev / c / asyncio.lha / AsyncIO / src / OpenAsyncFH.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-13  |  5.8 KB  |  214 lines

  1. #include "async.h"
  2.  
  3. #ifdef ASIO_NOEXTERNALS
  4. struct AsyncFile*
  5. AS_OpenAsyncFH(
  6.     BPTR handle,
  7.     OpenModes mode,
  8.     LONG bufferSize,
  9.     BOOL closeIt,
  10.     struct ExecBase *SysBase,
  11.     struct DosLibrary *DOSBase )
  12. #else
  13. struct AsyncFile *
  14. AS_OpenAsyncFH( BPTR handle, OpenModes mode, LONG bufferSize, BOOL closeIt )
  15. #endif
  16. {
  17.     struct AsyncFile    *file;
  18.     struct FileHandle    *fh;
  19.     BPTR            lock;
  20.     LONG            blockSize;
  21.     LONG            blockSize2;
  22.     D_S( struct InfoData, infoData );
  23.  
  24.     file    = NULL;
  25.     lock    = NULL;
  26.  
  27.     if( mode == MODE_READ )
  28.     {
  29.         if( handle )
  30.         {
  31.             lock = DupLockFromFH( handle );
  32.         }
  33.     }
  34.     else
  35.     {
  36.         if( mode == MODE_APPEND )
  37.         {
  38.             /* in append mode, we open for writing, and then seek to the
  39.              * end of the file. That way, the initial write will happen at
  40.              * the end of the file, thus extending it
  41.              */
  42.  
  43.             if( handle )
  44.             {
  45.                 if( Seek( handle, 0, OFFSET_END ) < 0 )
  46.                 {
  47.                     if( closeIt )
  48.                     {
  49.                         Close( handle );
  50.                     }
  51.  
  52.                     handle = NULL;
  53.                 }
  54.             }
  55.         }
  56.  
  57.         /* we want a lock on the same device as where the file is. We can't
  58.          * use DupLockFromFH() for a write-mode file though. So we get sneaky
  59.          * and get a lock on the parent of the file
  60.          */
  61.         if( handle )
  62.         {
  63.             lock = ParentOfFH( handle );
  64.         }
  65.     }
  66.  
  67.     if( handle )
  68.     {
  69.         /* if it was possible to obtain a lock on the same device as the
  70.          * file we're working on, get the block size of that device and
  71.          * round up our buffer size to be a multiple of the block size.
  72.          * This maximizes DMA efficiency.
  73.          */
  74.  
  75.         blockSize = 512;
  76.         blockSize2 = 1024;
  77.  
  78.         if( lock )
  79.         {
  80.             if( Info( lock, infoData ) )
  81.             {
  82.                 blockSize = infoData->id_BytesPerBlock;
  83.                 blockSize2 = blockSize * 2;
  84.                 bufferSize = ( ( bufferSize + blockSize2 - 1 ) / blockSize2 ) * blockSize2;
  85.             }
  86.  
  87.             UnLock(lock);
  88.         }
  89.  
  90.         /* now allocate the ASyncFile structure, as well as the read buffers.
  91.          * Add 15 bytes to the total size in order to allow for later
  92.          * quad-longword alignement of the buffers
  93.          */
  94.  
  95.         for( ;; )
  96.         {
  97.             if( file = AllocVec( sizeof( AsyncFile ) + bufferSize + 15, MEMF_PUBLIC | MEMF_ANY ) )
  98.             {
  99.                 break;
  100.             }
  101.             else
  102.             {
  103.                 if( bufferSize > blockSize2 )
  104.                 {
  105.                     bufferSize -= blockSize2;
  106.                 }
  107.                 else
  108.                 {
  109.                     break;
  110.                 }
  111.             }
  112.         }
  113.  
  114.         if( file )
  115.         {
  116.             file->af_File        = handle;
  117.             file->af_ReadMode    = ( mode == MODE_READ );
  118.             file->af_BlockSize    = blockSize;
  119.  
  120.             /* initialize the ASyncFile structure. We do as much as we can here,
  121.              * in order to avoid doing it in more critical sections
  122.              *
  123.              * Note how the two buffers used are quad-longword aligned. This
  124.              * helps performance on 68040 systems with copyback cache. Aligning
  125.              * the data avoids a nasty side-effect of the 040 caches on DMA.
  126.              * Not aligning the data causes the device driver to have to do
  127.              * some magic to avoid the cache problem. This magic will generally
  128.              * involve flushing the CPU caches. This is very costly on an 040.
  129.              * Aligning things avoids the need for magic, at the cost of at
  130.              * most 15 bytes of ram.
  131.              */
  132.  
  133.             fh            = BADDR( file->af_File );
  134.             file->af_Handler    = fh->fh_Type;
  135.             file->af_BufferSize    = bufferSize / 2;
  136.             file->af_Buffers[ 0 ]    = ( APTR ) ( ( ( ULONG ) file + sizeof( struct AsyncFile ) + 15 ) & 0xfffffff0 );
  137.             file->af_Buffers[ 1 ]    = file->af_Buffers[ 0 ] + file->af_BufferSize;
  138.             file->af_Offset        = file->af_Buffers[ 0 ];
  139.             file->af_CurrentBuf    = 0;
  140.             file->af_SeekOffset    = 0;
  141.             file->af_PacketPending    = FALSE;
  142.             file->af_Received    = 0;
  143.             file->af_CloseFH    = closeIt;
  144. #ifdef ASIO_NOEXTERNALS
  145.             file->af_SysBase    = SysBase;
  146.             file->af_DOSBase    = DOSBase;
  147. #endif
  148.  
  149.             /* this is the port used to get the packets we send out back.
  150.              * It is initialized to PA_IGNORE, which means that no signal is
  151.              * generated when a message comes in to the port. The signal bit
  152.              * number is initialized to SIGB_SINGLE, which is the special bit
  153.              * that can be used for one-shot signalling. The signal will never
  154.              * be set, since the port is of type PA_IGNORE. We'll change the
  155.              * type of the port later on to PA_SIGNAL whenever we need to wait
  156.              * for a message to come in.
  157.              *
  158.              * The trick used here avoids the need to allocate an extra signal
  159.              * bit for the port. It is quite efficient.
  160.              */
  161.  
  162.             file->af_PacketPort.mp_MsgList.lh_Head        = ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Tail;
  163.             file->af_PacketPort.mp_MsgList.lh_Tail        = NULL;
  164.             file->af_PacketPort.mp_MsgList.lh_TailPred    = ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Head;
  165.             file->af_PacketPort.mp_Node.ln_Type        = NT_MSGPORT;
  166.             file->af_PacketPort.mp_Node.ln_Name        = NULL;
  167.             file->af_PacketPort.mp_Flags            = PA_IGNORE;
  168.             file->af_PacketPort.mp_SigBit            = SIGB_SINGLE;
  169.             file->af_PacketPort.mp_SigTask            = FindTask( NULL );
  170.  
  171.             file->af_Packet.sp_Pkt.dp_Link            = &file->af_Packet.sp_Msg;
  172.             file->af_Packet.sp_Pkt.dp_Arg1            = fh->fh_Arg1;
  173.             file->af_Packet.sp_Pkt.dp_Arg3            = file->af_BufferSize;
  174.             file->af_Packet.sp_Pkt.dp_Res1            = 0;
  175.             file->af_Packet.sp_Pkt.dp_Res2            = 0;
  176.             file->af_Packet.sp_Msg.mn_Node.ln_Name        = ( STRPTR ) &file->af_Packet.sp_Pkt;
  177.             file->af_Packet.sp_Msg.mn_Node.ln_Type        = NT_MESSAGE;
  178.             file->af_Packet.sp_Msg.mn_Length        = sizeof( struct StandardPacket );
  179.  
  180.             if( mode == MODE_READ )
  181.             {
  182.                 /* if we are in read mode, send out the first read packet to
  183.                  * the file system. While the application is getting ready to
  184.                  * read data, the file system will happily fill in this buffer
  185.                  * with DMA transfers, so that by the time the application
  186.                  * needs the data, it will be in the buffer waiting
  187.                  */
  188.  
  189.                 file->af_Packet.sp_Pkt.dp_Type    = ACTION_READ;
  190.                 file->af_BytesLeft        = 0;
  191.  
  192.                 if( file->af_Handler )
  193.                 {
  194.                     AS_SendPacket( file, file->af_Buffers[ 0 ] );
  195.                 }
  196.             }
  197.             else
  198.             {
  199.                 file->af_Packet.sp_Pkt.dp_Type    = ACTION_WRITE;
  200.                 file->af_BytesLeft        = file->af_BufferSize;
  201.             }
  202.         }
  203.         else
  204.         {
  205.             if( closeIt )
  206.             {
  207.                 Close( handle );
  208.             }
  209.         }
  210.     }
  211.  
  212.     return( file );
  213. }
  214.